import "component";

var adc = require("adc");
var fs = require("fs");
var buf = require("buffer");
var net = require("net");
var udp = require("udp");

var cat_buf = buf.alloc(2048);
var cat_rxbuf = buf.alloc(2048);

var pingFlag = true;
var isConnected = false;

function loadConfigCallback(err, fd){
	print("loadConfigCallback");
	var size = fs.size(fd);
	print(size);
	if(size < 2048)
	{
		fs.read(fd, cat_buf, size);
		var obj = json.parse(cat_buf);
		var jsonArray = json.item(obj, "c");
		if(typeof(jsonArray) != "undefined"){
			var len = json.size(jsonArray);
			var i = 0;
			var j = 0;
			if(typeof(len) == "number"){
				while(i < len){
					var localObj = json.item(jsonArray, i);
					var name = json.item(localObj, "n");
					var type = json.item(localObj, "t");
					var addr = json.item(localObj, "a");
					
					if(typeof(findComp(addr, name)) == "undefined"){
						var comp = createRawComp(name, type, addr);
						
						if(address < addr){
							address = addr;
						}
						
						var localArray = json.item(localObj, "p");
						var size = json.size(localArray);
						j = 0;
						while(j < size){
							var objLocal = json.item(localArray, j);
							var n = json.item(objLocal, "n");
							var v = json.item(objLocal, "v");
							comp.props.push(createValue(n, v));
							j++;
						}
					}
					i++;
				}
			}
		}
		i = 0;
		jsonArray = json.item(obj, "l");
		if(typeof(jsonArray) != "undefined"){
			len = json.size(jsonArray);
			if(typeof(len) == "number"){
				while(i < len){
					localObj = json.item(jsonArray, i);
					var sc = json.item(localObj, "sc");
					var ss = json.item(localObj, "ss");
					var tc = json.item(localObj, "tc");
					var ts = json.item(localObj, "ts");
					i++;
					createLink(sc, ss, tc, ts);
				}
			}
		}
		
		json.delete(obj);
	}
	else{
		print("Failed to load config file");
	}
	fs.close(fd);
}

function reply_error(){
	var jsonObj = json.createObject();
	json.insert(jsonObj, "c", "error");	
	json.toJson(jsonObj, "formatted", cat_buf);
	json.delete(jsonObj);
	net.write(cat_buf, string.size(cat_buf));
}

function reply_ok(cmd){
	var jsonObj = json.createObject();
	json.insert(jsonObj, "c", cmd);	
	json.toJson(jsonObj, "formatted", cat_buf);
	json.delete(jsonObj);
	net.write(cat_buf, string.size(cat_buf));
}

function fileOpenCallBack(err, fd){
	fs.write(fd, cat_buf, string.size(cat_buf));
	fs.close(fd);
}

function loadConfig(){
	fs.open("config.jsn", "r", loadConfigCallback);
}

function readPropReq(obj){
	var jsonArray = json.item(obj, "p");
	var i = 0;
	if(typeof(jsonArray) == "undefined")
	{
		print("invalid json format");
		reply_error();
		return;
	}
	
	var len = json.size(jsonArray);
	
	if(len == 0){
		print("json array size can't be zero");
		reply_error();
		return;
	}
	
	var addr = json.item(obj, "a");
	
	var jsonObj = json.createObject();
	var localArray = json.createArray();
	var type = json.item(obj, "t");
	json.insert(jsonObj, "c", "r");
	json.insert(jsonObj, "a", addr);
	json.insert(jsonObj, "p", localArray);
	json.insert(jsonObj, "t", type);
	while(i < len){
		var localObj = json.item(jsonArray, i);
		var name = json.item(localObj, "n");
		var prop = findProp(addr, name);
		if(typeof(prop) == "undefined"){
			print(name);
			print("no such prop");
			reply_error();
			json.delete(jsonObj);
			return;
		}else{
			var propObj = json.createObject();
			json.insert(propObj, "n", name);
			json.insert(propObj, "v", prop.value);
			json.insert(localArray,propObj);
		}
		i++;
	}
	json.toJson(jsonObj, "formatted", cat_buf);
	json.delete(jsonObj);
	net.write(cat_buf, string.size(cat_buf));
}

function fileClearCallBack(err, fd){
	fs.write(fd, "");
	fs.close(fd);
}

function clearConfig(){
	fs.open("config.jsn", "rw", fileClearCallBack);
	reply_ok("c");
}

function readCompReq(obj){

}

function invokeReq(obj){
	
}

function writeAllReq(obj){
	var jsonArray = json.item(obj, "p");
	var i = 0;
	var j = 0;
	if(typeof(jsonArray) == "undefined")
	{
		print("invalid json format");
		reply_error();
		return;
	}
	
	var len = json.size(jsonArray);
	
	if(typeof(len) != "number"){
		print("json array size can't be zero");
		reply_error();
		return;
	}
	
	print(len);
	
	while(i < len){
		var localObj = json.item(jsonArray, i);
		var addr = json.item(localObj, "a");
		var name = json.item(localObj, "n");
		var comp = findComp(addr, name);
		if(typeof(comp) != "undefined"){
			j = 0;
			var localArray = json.item(localObj, "p");
			var propLen = json.size(localArray);
			if(typeof(propLen) == "number"){
				print(propLen);
				while(j < propLen){
					var propObj = json.item(localArray, j);
					var n = json.item(propObj, "n");
					var v = json.item(propObj, "v");
					var prop = findProp(addr, n);
					if(typeof(prop) != "undefined"){
						prop.value = v;
					}
					else
						print("can't find prop");
					print(j);
					j++;
				}
			}
		}
		else
			print("can't find comp");
		print(i);
		i++;
	}
	print("writeAllReq");
	reply_ok("wa");
}

function writeReq(obj){
	var jsonArray = json.item(obj, "p");
	var i = 0;
	if(typeof(jsonArray) == "undefined")
	{
		print("invalid json format");
		reply_error();
		return;
	}
	
	var len = json.size(jsonArray);
	
	if(len == 0){
		print("json array size can't be zero");
		reply_error();
		return;
	}
	
	var addr = json.item(obj, "a");
	
	while(i < len){
		var localObj = json.item(jsonArray, i);
		var name = json.item(localObj, "n");
		var val = json.item(localObj, "v");
		var prop = findProp(addr, name);
		if(typeof(prop) == "undefined"){
			print("no such prop");
			reply_error();
			return;
		}else{
			if(checkValType(val, prop))
				prop.value = val;
		}
		i++;
	}
	reply_ok("w");
}

function addReq(obj){	
	var name = json.item(obj, "n");
	var type = json.item(obj, "t");
	var comp = createComp(name, type, address);
	
	var jsonArray = json.item(obj, "p");
	var i = 0;
	var len = json.size(jsonArray);
	print(len);
	while(i < len)
	{
		var jsonObj = json.item(jsonArray, i);
		var n = json.item(jsonObj, "n");
		var v = json.item(jsonObj, "v");
		comp.props.push(createValue(n, v));
		i++;
	}
	
	var jsonObj = json.createObject();
	json.insert(jsonObj, "c", "a");
	json.insert(jsonObj, "n", name);
	json.insert(jsonObj, "t", type);
	json.insert(jsonObj, "a", comp.addr);
	
	json.toJson(jsonObj, "formatted", cat_buf);
	json.delete(jsonObj);
	net.write(cat_buf, string.size(cat_buf));
	print(cat_buf);
}

function deleteReq(obj){
	var name = json.item(obj, "n");
	var addr = json.item(obj, "a");
	var comp = findComp(addr, name);
	if(typeof(comp) == "undefined"){
		reply_error();
		return;
	}
	
}

function renameReq(obj){
	
}

function reorderReq(obj){
	//reorder component
}

function linkReq(obj){
	var sc = json.item(obj, "sc");
	var ss = json.item(obj, "ss");
	var tc = json.item(obj, "tc");
	var ts = json.item(obj, "ts");
	
	createLink(sc, ss, tc, ts);
	reply_ok("l");
	print("linkReq");
}

function queryReq(obj){
	var jsonArray = json.createArray();
	var index = 0;
	while(index < root.length())
	{
		var comp = root[index];
		var jsonObj = json.createObject();
		json.insert(jsonObj, "n", comp.name);
		json.insert(jsonObj, "t", comp.type);
		json.insert(jsonObj, "a", comp.addr);
		
		json.insert(jsonArray, jsonObj);
		index++;
	}
	json.toJson(jsonArray, "formatted", cat_buf);
	json.delete(jsonArray);
	net.write(cat_buf, string.size(cat_buf));	
	print("queryReq");
}

function fileOpenReq(obj){
	
}

function fileCloseReq(obj){
	
}

function fileRenameReq(obj){
	
}

function getConfigFileCB(err, fd){
	var size = fs.size(fd);
	print(size);
	if(size < 4096)
	{
		fs.read(fd, cat_buf, size);
		net.write(cat_buf, size);
	}
	fs.close(fd);
}

function getConfigReq(){
	fs.open("config.jsn", "r", getConfigFileCB);
}

var text;

function fileSaveJsonCB(err, fd){
	print(text);
	fs.write(fd, text);
	fs.close(fd);
}

function saveJsonReq(obj){
	text = json.item(obj, "v");
	fs.open("config.jsn", "rw", fileSaveJsonCB);
	reply_ok("sj");
	print("saveJsonReq");
}

function saveConfigReq(obj){
	var jsonObject = json.createObject();
	var compArray = json.createArray();
	var linkArray = json.createArray();
	var index = 0;
	var propIndex = 0;
	
	json.insert(jsonObject, "c", compArray);
	json.insert(jsonObject, "l", linkArray);
	
	while(index < root.length())
	{
		var comp = root[index];
		var jsonObj = json.createObject();
		print(comp);
		json.insert(jsonObj, "n", comp.name);
		json.insert(jsonObj, "t", comp.type);
		json.insert(jsonObj, "a", comp.addr);
		
		var propArray = json.createArray();
		json.insert(jsonObj, "p", propArray);
		propIndex = 0;
		while(propIndex < comp.props.length())
		{
			var val = comp.props[propIndex];
			var propObj = json.createObject();
			json.insert(propObj, "n", val.name);
			json.insert(propObj, "v", val.value);
			propIndex++;
			
			json.insert(propArray, propObj);
		}
		
		json.insert(compArray, jsonObj);
		index++;
	}
	
	index = 0;
	while(index < links.length())
	{
		var localLink = links[index];
		var jsonObj = json.createObject();
		json.insert(jsonObj, "sc", localLink.sc);
		json.insert(jsonObj, "ss", localLink.ss);
		json.insert(jsonObj, "tc", localLink.tc);
		json.insert(jsonObj, "ts", localLink.ts);
		
		json.insert(linkArray, jsonObj);
		index++;
	}
	
	json.toJson(jsonObject, "formatted", cat_buf);
	json.delete(jsonObject);
	
	fs.open("config.jsn", "rw", fileOpenCallBack);
	
	reply_ok("s");
	print("saveConfigReq");
}

function pingReq(obj){
	
	pingFlag = true;
	var jsonObj = json.createObject();
	json.insert(jsonObj, "c", "p");	
	json.toJson(jsonObj, "formatted", cat_buf);
	json.delete(jsonObj);
	net.write(cat_buf, string.size(cat_buf));

}

function cat_process(msg){
	var cmd;
	var obj = json.parse(msg);
	print(msg);
	if(typeof(obj) == "undefined")
	{
		print("not cmd format");
		return;
	}
	var cmd = json.item(obj, "c");
	if(cmd == "a") addReq(obj);
	else if(cmd == "r") readPropReq(obj); 
	else if(cmd == "w") writeReq(obj);
	else if(cmd == "c") clearConfig();
	else if(cmd == "i") invokeReq(obj);
	else if(cmd == "d") deleteReq(obj);
	else if(cmd == "n") renameReq(obj);
	else if(cmd == "o") reorderReq(obj);
	else if(cmd == "l") linkReq(obj);
	else if(cmd == "q") queryReq(obj);
	else if(cmd == "f") fileOpenReq(obj);
	else if(cmd == "z") fileCloseReq(obj);
	else if(cmd == "s") saveConfigReq(obj);
	else if(cmd == "sj") saveJsonReq(obj);
	else if(cmd == "g") getConfigReq(obj);
	else if(cmd == "p") pingReq(obj);
	else if(cmd == "wa") writeAllReq(obj);
	else print("bad cmd");
	json.delete(obj);
}

var timerId;

function pingCallback(){
	if(isConnected)
	{
		print("pingCallback");
		if(pingFlag)
		{
			pingFlag = false;
		}
		else
		{
			net.close();
			isConnected = false;
			print("close socket, timeout");
			net.listen(2017);
			clearInterval(timerId);
		}
	}
}

function connect_callback(){
	print("socket connected!");
	isConnected = true;
	pingFlag = true;
	timerId = setInterval(pingCallback, 10000);
}

function close_callback(){
	net.close();
	isConnected = false;
	print("close socket, timeout");
	net.listen(2017);
	clearInterval(timerId);
}


function data_callback(size){
	net.read(cat_rxbuf, size);
	cat_process(cat_rxbuf);

}


net.listen(2017);
net.on("connected", connect_callback);
net.on("data", data_callback);
net.on("close", close_callback);

function udp_listener(size)
{
	print(size);
	udp.read(cat_buf, size);
	print(cat_buf.toString());
	var cmd;
	var obj = json.parse(cat_buf.toString());
	if(typeof(obj) == "undefined")
	{
		return;
	}
	
	cmd = json.item(obj, "vendor");
	print(cmd);
	cmd = json.item(obj, "device");
	print(cmd);
	json.delete(obj);
	
	var jsonObj = json.createObject();
	json.insert(jsonObj, "ip", udp.localIp());
	json.insert(jsonObj, "name", "jsduino");
	json.toJson(jsonObj, "formatted", cat_buf);
	print(cat_buf.toString());
	var jsonStr = cat_buf.toString();
	json.delete(jsonObj);
	print(udp.remoteIp());
	print(udp.remotePort());
	udp.write(jsonStr, udp.remoteIp(), 9999);
}

udp.bind(8888);
udp.on("data", udp_listener);

loadConfig();

function loop(){
	while(true){

	}
}

adc.init(0);

function compHandler(){
	var prop = findPropByComp(adcPoint, "out");
	prop.value = adc.read(0);
}

setInterval(compHandler, 100);

loop();
